package com.leenmvc.core.base;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.leenmvc.core.dao.communal.BaseDao;
import com.leenmvc.core.dao.communal.CommonWrapper;
import com.leenmvc.core.dao.communal.Wrapper;
import com.leenmvc.core.dao.mysql.wrapper.*;
import com.leenmvc.core.exception.ValidatorException;
import com.leenmvc.core.security.entity.core.SysDict;
import com.leenmvc.core.utils.BeanUtils;
import com.leenmvc.core.utils.collection.MapUtils;
import com.leenmvc.core.utils.dictionary.DictGet;
import com.leenmvc.core.utils.dictionary.DictGetImpl;
import com.leenmvc.core.utils.validator.ValidatorUtils;
import com.leenmvc.core.base.result.PageData;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

/**
 * 数据库查询
 * 三层结构中的 视图表现层和服务层都继承这个类
 *
 */
public class BaseDbHandler implements DictGet, CommonWrapper {

    /**
     * 字典方法快速获取
     */
    private DictGet dictDao = DictGetImpl.getInstance();

    /**
     * 根据实体获取BaseDao句柄（方言选择）
     *
     * @param entity
     * @return
     */
    private BaseDao baseDao(Class<?> entity) {
        return BaseEntity.getDialect(entity).getBaseDao();
    }

    /**
     *
     * @param id
     * @return
     */
    @Override
    public SysDict dictId(Object id) {
        return dictDao.dictId(id);
    }

    @Override
    public List<SysDict> dictType(String dictType) {
        return dictDao.dictType(dictType);
    }

    @Override
    public Map<String, Object> getMapByType(String dictType) {
        return dictDao.getMapByType(dictType);
    }


    @Override
    public List<SysDict> typeListRidPid(String dictType) {
        return dictDao.typeListRidPid(dictType);
    }

    @Override
    public List<SysDict> dictPid(Object pid) {
        return dictDao.dictPid(pid);
    }

    @Override
    public SysDict typeNameDict(String type, String name) {
        return dictDao.typeNameDict(type, name);
    }

    @Override
    public String typeNameGet(String type, String name) {
        return dictDao.typeNameGet(type, name);
    }

    @Override
    public boolean dictInsert(SysDict sysDict) {
        return dictDao.dictInsert(sysDict);
    }

    @Override
    public boolean dictUpdate(SysDict sysDict) {
        return dictDao.dictUpdate(sysDict);
    }

    @Override
    public int dictUpdate(Map<String, Object> params) {
        return dictDao.dictUpdate(params);
    }

    @Override
    public boolean dictDelete(SysDict sysDict) {
        return dictDao.dictDelete(sysDict);
    }

    @Override
    public boolean dictDelete(Object id) {
        return dictDao.dictDelete(id);
    }

    @Override
    public QueryWrapper getQueryWrapper() {
        Class<?> classType = getClassType();
        return BaseEntity.getDialect(classType).getWrapperFactory().getQueryWrapper(classType);
    }

    @Override
    public <T> T getQueryWrapper(Class<?> cls) {
        return BaseEntity.getDialect(cls).getWrapperFactory().getQueryWrapper(cls);
    }

    public <T> T getQueryWrapper(Map<String, Object> params) {
        Class<?> classType = getClassType();
        return BaseEntity.getDialect(classType).getWrapperFactory().getQueryWrapper(classType, params);
    }

    @Override
    public <T> T getUpdateWrapper(T t) {
        Class<?> aClass = t.getClass();
        return BaseEntity.getDialect(aClass).getWrapperFactory().getUpdateWrapper(t);
    }

    @Override
    public <T> T getUpdateWrapper(Class<?> cls) {
        return BaseEntity.getDialect(cls).getWrapperFactory().getUpdateWrapper(cls);
    }

    public <T> T getUpdateWrapper(Map<String, Object> params) {
        Class<?> classType = getClassType();
        return BaseEntity.getDialect(classType).getWrapperFactory().getUpdateWrapper(getClassType(), params);
    }

    @Override
    public <T> T getUpdateWrapper(Class<?> cls, Map<String, Object> params) {
        return  BaseEntity.getDialect(cls).getWrapperFactory().getUpdateWrapper(cls, params);
    }

    @Override
    public CountWrapper getCountWrapper() {
        Class<?> classType = getClassType();
        return BaseEntity.getDialect(classType).getWrapperFactory().getCountWrapper(classType);
    }

    @Override
    public <T> T getCountWrapper(Class<?> cls) {
        return  BaseEntity.getDialect(cls).getWrapperFactory().getCountWrapper(cls);
    }

    @Override
    public DeleteWrapper getDeleteWrapper() {
        Class<?> classType = getClassType();
        return  BaseEntity.getDialect(classType).getWrapperFactory().getDeleteWrapper(classType);
    }

    @Override
    public <T> T getDeleteWrapper(Class<?> cls) {
        return BaseEntity.getDialect(cls).getWrapperFactory().getDeleteWrapper(cls);
    }

    public <T> List<T> getPageList(Wrapper queryWrapper) {
        return baseDao(queryWrapper.getCls()).getPageList(queryWrapper);
    }

    public int count(Wrapper queryWrapper) {
        return baseDao(queryWrapper.getCls()).count(queryWrapper);
    }

    public <T> List<T> query(Wrapper queryWrapper) {
        return baseDao(queryWrapper.getCls()).query(queryWrapper);
    }

    public <T> T get(Wrapper queryWrapper) {
        return baseDao(queryWrapper.getCls()).get(queryWrapper);
    }

    public <T> List<T> getList(Object...kvs) {
        Class<?> classType = getClassType();
        return baseDao(classType).getList(classType, kvs);
    }

    public <T> T get(Object...kvs) {
        Class<?> classType = getClassType();
        return baseDao(classType).get(classType, kvs);
    }

    public <T> List<T> getList(Map<String,Object> params) {
        Class<?> classType = getClassType();
        return baseDao(classType).getList(classType, params);
    }
    /**
     * 返回的是一个值
     * @param queryWrapper
     * @param <T>
     * @return
     */
    public <T> T getOneField(Wrapper queryWrapper) {
        return baseDao(queryWrapper.getCls()).getOneField(queryWrapper);
    }

    /**
     * 返回的是一个值的数组
     * @param queryWrapper
     * @param <T>
     * @return
     */
    public <T> List<T> getOneFieldList(Wrapper queryWrapper) {
        return baseDao(queryWrapper.getCls()).oneFieldList(queryWrapper);
    }


    public Map<String, Object> getMap(Wrapper queryWrapper) {
        return baseDao(queryWrapper.getCls()).getMap(queryWrapper);
    }

    public List<Map<String, Object>> getListMap(Wrapper queryWrapper) {
        return baseDao(queryWrapper.getCls()).getListMap(queryWrapper);
    }

    public int delByWrapper(Wrapper wrapper) {
        return baseDao(wrapper.getCls()).delByWrapper(wrapper);
    }

    public int delete(Object... kvs) {
        Class<?> classType = getClassType();
        return baseDao(classType).delete(classType, kvs);
    }

    public int updateByWrapper(Wrapper queryWrapper) {
        return baseDao(queryWrapper.getCls()).updateByWrapper(queryWrapper);
    }

    public boolean deleteById(Object id) {
        Class<?> classType = getClassType();
        return baseDao(classType).deleteById(classType, id);
    }

    public int deleteByIds(Object[] ids) {
        Class<?> classType = getClassType();
        return baseDao(classType).deleteByIds(getClassType(), ids);
    }

    public int deleteByIds(Class<?> cls, Object[] ids) {
        return baseDao(cls).deleteByIds(cls, ids);
    }

    public <T> boolean remove(T t) {
        return baseDao(t.getClass()).remove(t);
    }

    public <T> int batchRemove(List<T> list) {
        return baseDao(list.get(0).getClass()).batchRemove(list);
    }

    public <T> T get(Object id) {
        Class<?> classType = getClassType();
        return baseDao(classType).get(classType, id);
    }

    public <T> T get(Class<?> cls, Object id) {
        return baseDao(cls).get(cls, id);
    }

    public <T> T get(Map<String, Object> params) {
        Class<?> classType = getClassType();
        return baseDao(classType).get(classType, params);
    }

    public <T> List<T> getPageList(Integer... pageInfo) {
        Class<?> classType = getClassType();
        return baseDao(classType).getPageList(classType, pageInfo);
    }

    public <T> List<T> getPageList(Map<String, Object> conditions, Integer... pageInfo) {
        Class<?> classType = getClassType();
        return baseDao(classType).getPageList(classType, conditions, pageInfo);
    }

    public <T> List<T> getAll() {
        Class<?> classType = getClassType();
        return baseDao(classType).getAll(classType);
    }

    public <T> List<T> query(String sql, Object... objects) {
        Class<?> classType = getClassType();
        return baseDao(classType).query(classType, sql, objects);
    }

    public Map<String, Object> getMap(String sql, Object... objects) {
        Class<?> classType = getClassType();
        return baseDao(classType).getMap(classType, sql, objects);
    }

    public List<Map<String, Object>> getListMap(String sql, Object... objects) {
        Class<?> classType = getClassType();
        return baseDao(classType).getListMap(classType, sql, objects);
    }

    public <T> boolean insert(T t) {
        Class<?> classType = t.getClass();
        return baseDao(classType).insert(t);
    }
    public <T> boolean saveOrUpdate(T t) {
        Class<?> classType = t.getClass();
        return baseDao(classType).saveOrUpdate(t);
    }
    public <T> boolean insert(Map<String, Object> entityMap) {
        Class<?> classType = getClassType();
        return baseDao(classType).insert(classType, entityMap);
    }

    public <T> boolean batchInsert(List<T> t) {
        return baseDao(t.getClass()).batchInsert(t);
    }

    public <T> boolean batchInsert(T[] ts) {
        return baseDao(ts[0].getClass()).batchInsert(ts);
    }

    public <T> boolean update(T t) {
        return baseDao(t.getClass()).update(t);
    }

    public <T> boolean update(Object id, Object... kv) {
        Class<?> classType = getClassType();
        return baseDao(classType).update(classType, id, kv);
    }

    public <T> int update(Map<String, Object> params) {
        Class<?> classType = getClassType();
        return baseDao(classType).update(classType, params);
    }

    public int count(Map<String, Object> params) {
        Class<?> classType = getClassType();
        return baseDao(classType).count(classType, params);
    }

    public int count(Object... kvs) {
        Class<?> classType = getClassType();
        return baseDao(classType).count(classType, kvs);
    }

    public int count() {
        Class<?> classType = getClassType();
        return baseDao(classType).count(classType);
    }

    /**
     * 通过mybaties 写复杂sql用的
     * @param id
     * @param params
     * @param <T>
     * @return
     */
    public <T> List<T> listBySqlKey(String id, Map<String, Object> params) {
        Class<?> classType = getClassType();
        return baseDao(classType).listBySqlKey(classType, id, params);
    }

    /**
     * 通过mybaties 写复杂sql用的
     * @param id
     * @param params
     * @param <T>
     * @return
     */
    public <T> List<T> listBySqlKey(Class<?> cls, String id, Map<String, Object> params) {
        return baseDao(cls).listBySqlKey(cls, id, params);
    }

    /**
     * 通过mybaties 写复杂sql用的
     * @param id
     * @param params
     * @param <T>
     * @return
     */
    public <T> List<T> listBySqlKey(Class<?> cls, String id, Object...params) {
        return baseDao(cls).listBySqlKey(cls, id, params);
    }

    public <T> T getBySqlKey(String id, Map<String, Object> params) {
        Class<?> classType = getClassType();
        return baseDao(classType).getBySqlKey(classType, id, params);
    }

    public <T> List<T> listBySqlKey(String id, Object param) {
        Class<?> classType = getClassType();
        return baseDao(classType).listBySqlKey(classType, id, param);
    }

    public <T> T getBySqlKey(String id, Object param) {
        Class<?> classType = getClassType();
        return baseDao(classType).getBySqlKey(classType, id, param);
    }


    public <T> List<T> listBySqlKey(String id, Object...param) {
        Class<?> classType = getClassType();
        return baseDao(classType).listBySqlKey(classType, id, param);
    }

    public <T> T getBySqlKey(String id, Object...param) {
        Class<?> classType = getClassType();
        return baseDao(classType).getBySqlKey(classType, id, param);
    }

    public <T> PageData<T> getPage(int page, int pageSize) {
        List<T> pageList = getPageList(page, pageSize);
        return new PageData(page, pageSize, count(), pageList);
    }

    public <T> PageData<T> getPage(String mybatisKey, Map<String, Object> params) {
        PageHelper.startPage(MapUtils.getInteger(params, "page", PageData.DEFAULT_PAGE), MapUtils.getInteger(params, "pageSize", PageData.DEFAULT_PAGESIZE));
        List<T> pageList = listBySqlKey(mybatisKey, params);
        PageInfo<T> pageInfo = new PageInfo<>(pageList);
        return new PageData(pageInfo.getPageNum(), pageInfo.getPageSize(), Integer.parseInt(pageInfo.getTotal() + ""), pageList);
    }

    public <T> PageData<T> getPage(Class<?> cls, String mybatisKey, Map<String, Object> params) {
        PageHelper.startPage(MapUtils.getInteger(params, "page", PageData.DEFAULT_PAGE), MapUtils.getInteger(params, "pageSize", PageData.DEFAULT_PAGESIZE));
        List<T> pageList = listBySqlKey(cls, mybatisKey, params);
        PageInfo<T> pageInfo = new PageInfo<>(pageList);
        return new PageData(pageInfo.getPageNum(), pageInfo.getPageSize(), Integer.parseInt(pageInfo.getTotal() + ""), pageList);
    }

    public <T> PageData<T> getPage(Map<String, Object> params, int page, int pageSize) {
        Map<String, Object> cloneMap = BeanUtils.deepClone(params);
        List<T> pageList = getPageList(params, page, pageSize);
        return new PageData(page, pageSize, count(cloneMap), pageList);
    }

    public <T> PageData<T> getPage(Wrapper wrapper, int page, int pageSize) {
        Wrapper countWrapper = getCountWrapper(wrapper.getCls());
        countWrapper.copy(wrapper);
        wrapper.limit(page, pageSize);
        List<T> pageList = getPageList(wrapper);
        return new PageData(page, pageSize, count(countWrapper), pageList);
    }

    public <T> PageData<T> getPage(Wrapper wrapper) {
        Wrapper countWrapper = getCountWrapper(wrapper.getCls());
        countWrapper.copy(wrapper);
        int page = wrapper.getLimit()[0];
        int pageSize = wrapper.getLimit()[1];
        int count = count(countWrapper);
        List<T> pageList = getPageList(wrapper);
        return new PageData(page, pageSize, count, pageList);
    }

    /**
     *
     * @param params
     * @param <T>
     * @return
     */
    public <T> PageData<T> getPage(Map<String, Object> params) {

        int page = PageData.DEFAULT_PAGE;
        int pageSize = PageData.DEFAULT_PAGESIZE;

        if(params.get("page") != null) {
            page = ValidatorUtils.convertToNum("页数(page)必须为数字且为正整数", params.get("page"), Integer.class);
            if(page <= 0) throw new ValidatorException("页数(page)必须为数字且为正整数");
            params.remove("page");
        }

        if(params.get("pageSize") != null) {
            pageSize = ValidatorUtils.convertToNum("页大小(pageSize)必须为数字且为正整数", params.get("pageSize"), Integer.class);
            if(pageSize <= 0) throw new ValidatorException("页大小(pageSize)必须为数字且为正整数");
            params.remove("pageSize");
        }

        List<T> pageList = getPageList(params, page, pageSize);
        return new PageData(page, pageSize, count(params), pageList);
    }

    /**
     * 获取父类型的泛型信息
     *
     * @return
     *
     */
    protected Class<?> getClassType() {
        Type type = this.getClass().getGenericSuperclass();
        ParameterizedType pt = (ParameterizedType) type;
        Type[] ts = pt.getActualTypeArguments();
        Class c = (Class) ts[0];
        return c;
    }


}
